<?php
	/* Functions in this file */
	/**************************/

	// AddComplexSymbol($symbolData)
	// ClearArtificialHarmonic()
	// ClearBend()
	// ClearComplexSymbolArrayContents()
	// ClearSimpleFlag($flag)
	// ClearSlideInto()
	// ClearSlideOutOf()
	// ClearTappedHarmonic()
	// ClearTrill()
	// FindComplexSymbol($type)
	// GetComplexSymbolCount()
	// GetFretNumber()
	// GetMFCClassName()
	// GetMFCClassSchema()
	// GetSlideInto(&$type)
	// GetString()
	// GetTappedHarmonic(&$tappedFretNumber)
	// GetTrill(&$trilledFretNumber)
	// HasArtificialHarmonic()
	// HasBend()
	// HasHammerOn()
	// HasHammerOnFromNowhere()
	// HasPullOff()
	// HasPullOffToNowhere()
	// HasSlide()
	// HasSlideInto()
	// HasSlideOutOf()
	// HasTappedHarmonic()
	// HasTieWrap()
	// HasTrill()
	// IsGhostNote()
	// IsMuted()
	// IsNaturalHarmonic()
	// IsOctave8va()
	// IsOctave8vb()
	// IsOctave15ma()
	// IsOctave15mb()
	// IsSimpleFlagSet($flag)
	// IsTied()
	// IsValidArtificialHarmonicOctave($octave)
	// IsValidBendDuration($duration)
	// IsValidBendType($type)
	// IsValidBentPitch($bentPitch)
	// IsValidComplexSymbolType($type)
	// IsValidDrawEndPoint($drawEndPoint)
	// IsValidDrawStartPoint($drawStartPoint)
	// IsValidFretNumber($fretNumber)
	// IsValidReleasePitch($releasePitch)
	// IsValidSimpleFlag($flag)
	// IsValidSlideInto($type)
	// IsValidSlideIntoType($type)
	// IsValidSlideOutOf($type)
	// IsValidSlideOutOfType($type)
	// IsValidString($string)
	// IsValidTappedFretNumber($tappedFretNumber)
	// IsValidTappedHarmonic($tappedFretNumber)
	// IsValidTrill($trilledFretNumber)
	// IsValidTrilledFretNumber($trilledFretNumber)
	// RemoveComplexSymbol($type)
	// SetFretNumber($fretNumber)
	// SetSimpleFlag($flag)
	// SetSlideInto($type)
	// SetString($string)
	// SetTappedHarmonic($tappedFretNumber)
	// SetTrill($trilledFretNumber)
?>
<?php

	//include "chordname.php";
	 
	define('MAX_NOTE_COMPLEX_SYMBOLS',3);
	 
	class Note {
		 
		 
		// Constants
		// Default Constants
		const DEFAULT_STRING_DATA = 0;
		const DEFAULT_SIMPLE_DATA = 0;
		 
		// String Constants
		const MIN_STRING = 0;
		const MAX_STRING = 6;
		 
		// Fret Number Constants
		const MIN_FRET_NUMBER = 0;
		const MAX_FRET_NUMBER = 24;
		 
		// Bend Constants
		const MAX_BEND_PITCH = 12;
		const MAX_BEND_DURATION = 8;
		 
		 
		 
		const stringMask = 0x000000e0;
		const fretNumberMask = 0x0000001f;
		 
		 
		 
		const tied = 0x00000001;
		const muted = 0x00000002;
		const tieWrap = 0x00000004;
		const hammerOn = 0x00000008;
		const pullOff = 0x00000010;
		const hammerPullFromToNowhere = 0x00000020;
		const hammerPullMask = 0x00000038;
		const naturalHarmonic = 0x00000040;
		const ghostNote = 0x00000080;
		const octave8va = 0x00000100;
		const octave15ma = 0x00000200;
		const octave8vb = 0x00000400;
		const octave15mb = 0x00000800;
		const octaveMask = 0x00000f00;
		const simpleFlagsMask = 0x00000fff;
		 
		 
		 
		const slide = 100; //ord('d');
		const bend = 101; //ord('e');
		const tappedHarmonic = 102; //ord('f');
		const trill = 103; //ord('g');
		const artificialHarmonic = 104; //ord('h');
		const notUsed = 0;
		 
		 
		 
		const slideIntoNone = 0x00000000;
		const slideIntoFromBelow = 0x00000001;
		const slideIntoFromAbove = 0x00000002;
		const slideIntoShiftSlideUpwards = 0x00000003;
		const slideIntoShiftSlideDownwards = 0x00000004;
		const slideIntoLegatoSlideUpwards = 0x00000005;
		const slideIntoLegatoSlideDownwards = 0x00000006;
		 
		 
		 
		const slideOutOfNone = 0x00000000;
		const slideOutOfShiftSlide = 0x00000001;
		const slideOutOfLegatoSlide = 0x00000002;
		const slideOutOfDownwards = 0x00000003;
		const slideOutOfUpwards = 0x00000004;
		 
		 
		 
		const slideIntoTypeMask = 0x00ff0000;
		const slideOutOfTypeMask = 0x0000ff00;
		const slideOutOfStepsMask = 0x000000ff;
		 
		 
		 
		const normalBend = 0x00000000;
		const bendAndRelease = 0x00000001;
		const bendAndHold = 0x00000002;
		const preBend = 0x00000003;
		const preBendAndRelease = 0x00000004;
		const preBendAndHold = 0x00000005;
		const gradualRelease = 0x00000006;
		const immediateRelease = 0x00000007;
		 
		 
		 
		const lowPoint = 0x00000000;
		const midPoint = 0x00000001;
		const highPoint = 0x00000002;
		 
		 
		 
		const bendTypeMask = 0x00f00000;
		const drawStartMask = 0x000c0000;
		const drawEndMask = 0x00030000;
		const bendDurationMask = 0x0000ff00;
		const bentPitchMask = 0x000000f0;
		const releasePitchMask = 0x0000000f;
		 
		 
		 
		const artificialHarmonicOctaveLoco = 0x00000000;
		const artificialHarmonicOctave8va = 0x00000001;
		const artificialHarmonicOctave15ma = 0x00000002;
		 
		 
		// Member Variables
		 
		protected $m_stringData = self::DEFAULT_STRING_DATA;
		protected $m_simpleData = self::DEFAULT_SIMPLE_DATA;
		protected $m_complexSymbolArray = array();
		 
		 
		 
		// MFC Class Functions
		function DebugComplexArray() {
			print_r ($m_complexSymbolArray);
		}
		 
		function GetMFCClassName() {
			return "CLineData";
		}
		 
		 
		function GetMFCClassSchema() {
			return 1;
		}
		 
		// String Functions
		 
		 
		 
		function IsValidString($string) {
			return ($string <= self::MAX_STRING);
		}
		 
		// Fret Number Functions
		 
		 
		 
		function IsValidFretNumber($fretNumber) {
			return ($fretNumber <= self::MAX_FRET_NUMBER);
		}
		 
		// Tied Functions
		 
		 
		 
		function SetTied($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::tied));
				 return ($this->SetSimpleFlag(self::tied));
		}
		 
		 
		function IsTied() {
			return ($this->IsSimpleFlagSet(self::tied));
		}
		 
		// Muted Functions
		 
		 
		 
		function SetMuted($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::muted));
				 return ($this->SetSimpleFlag(self::muted));
		}
		 
		 
		function IsMuted() {
			return ($this->IsSimpleFlagSet(self::muted));
		}
		 
		// Tie Wrap Functions
		 
		 
		 
		function SetTieWrap($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::tieWrap));
				 return ($this->SetSimpleFlag(self::tieWrap));
		}
		 
		 
		function HasTieWrap() {
			return ($this->IsSimpleFlagSet(self::tieWrap));
		}
		 
		// Hammer On Functions
		 
		 
		 
		function SetHammerOn($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::hammerPullMask));
				 return ($this->SetSimpleFlag(self::hammerOn) && $this->ClearSimpleFlag(self::hammerPullFromToNowhere));
		}
		 
		 
		function HasHammerOn() {
			return ($this->IsSimpleFlagSet(self::hammerOn) && !$this->IsSimpleFlagSet(self::hammerPullFromToNowhere));
		}
		 
		 
		 
		function SetHammerOnFromNowhere($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::hammerPullMask));
				 return ($this->SetSimpleFlag(self::hammerOn | self::hammerPullFromToNowhere));
		}
		 
		 
		function HasHammerOnFromNowhere() {
			return ($this->IsSimpleFlagSet(self::hammerOn | self::hammerPullFromToNowhere));
		}
		 
		// Pull Off Functions
		 
		 
		 
		function SetPullOff($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::hammerPullMask));
				 return ($this->SetSimpleFlag(self::pullOff) && $this->ClearSimpleFlag(self::hammerPullFromToNowhere));
		}
		 
		 
		function HasPullOff() {
			return ($this->IsSimpleFlagSet(self::pullOff) && !$this->IsSimpleFlagSet(self::hammerPullFromToNowhere));
		}
		 
		 
		 
		function SetPullOffToNowhere($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::hammerPullMask));
				 return ($this->SetSimpleFlag(self::pullOff | self::hammerPullFromToNowhere));
		}
		 
		 
		function HasPullOffToNowhere() {
			return ($this->IsSimpleFlagSet(self::pullOff) && $this->IsSimpleFlagSet(self::hammerPullFromToNowhere));
		}
		 
		// Natural Harmonic Functions
		 
		 
		 
		function SetNaturalHarmonic($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::naturalHarmonic));
				 return ($this->SetSimpleFlag(self::naturalHarmonic));
		}
		 
		 
		function IsNaturalHarmonic() {
			return ($this->IsSimpleFlagSet(self::naturalHarmonic));
		}
		 
		// Ghost $this->Note Functions
		 
		 
		 
		function SetGhostNote($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::ghostNote));
				 return ($this->SetSimpleFlag(self::ghostNote));
		}
		 
		 
		function IsGhostNote() {
			return ($this->IsSimpleFlagSet(self::ghostNote));
		}
		 
		// 8va Octave Functions
		 
		 
		 
		function SetOctave8va($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::octave8va));
				 return ($this->SetSimpleFlag(self::octave8va));
		}
		 
		 
		function IsOctave8va() {
			return ($this->IsSimpleFlagSet(self::octave8va));
		}
		 
		// 15ma Octave Functions
		 
		 
		 
		function SetOctave15ma($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::octave15ma));
				 return ($this->SetSimpleFlag(self::octave15ma));
		}
		 
		 
		function IsOctave15ma() {
			return ($this->IsSimpleFlagSet(self::octave15ma));
		}
		 
		// 8vb Octave Functions
		 
		 
		 
		function SetOctave8vb($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::octave8vb));
				 return ($this->SetSimpleFlag(self::octave8vb));
		}
		 
		 
		function IsOctave8vb() {
			return ($this->IsSimpleFlagSet(self::octave8vb));
		}
		 
		// 15mb Octave Functions
		 
		 
		 
		function SetOctave15mb($set = 1) {
			if (!$set) return ($this->ClearSimpleFlag(self::octave15mb));
				 return ($this->SetSimpleFlag(self::octave15mb));
		}
		 
		 
		function IsOctave15mb() {
			return ($this->IsSimpleFlagSet(self::octave15mb));
		}
		 
		// Simple Flag Functions
		 
		// Determines if a $simple $flag is valid
		 
		 
		function IsValidSimpleFlag($flag) {
			return ((($flag & self::simpleFlagsMask) != 0) && (($flag & ~self::simpleFlagsMask) == 0));
		}
		 
		 
		function ClearSimpleFlag($flag) {
			if (!$this->IsValidSimpleFlag($flag)) return 0;
			$this->m_simpleData &= ~$flag;
			 return 1;
		}
		 
		 
		 
		function IsSimpleFlagSet($flag) {
			if (!$this->IsValidSimpleFlag($flag)) return 0;
			 return (($this->m_simpleData & $flag) == $flag);
		}
		 
		// Slide Functions
		 
		 
		function HasSlide() {
			return ($this->HasSlideInto() || $this->HasSlideOutOf());
		}
		 
		// Slide Into Functions
		 
		 
		 
		function IsValidSlideIntoType($type) {
			return ($type <= self::slideIntoLegatoSlideDownwards);
		}
		 
		 
		 
		function IsValidSlideInto($type) {
			return ($this->IsValidSlideIntoType($type));
		}
		 
		 
		// Slide Out Of Functions
		 
		 
		 
		function IsValidSlideOutOfType($type) {
			return ($type <= self::slideOutOfUpwards);
		}
		 
		 
		 
		function IsValidSlideOutOf($type) {
			return ($this->IsValidSlideOutOfType($type));
		}
		 
		 
		// Bend Functions
		 
		 
		function IsValidBendType($type) {
			return ($type <= self::immediateRelease);
		}
		 
		 
		 
		function IsValidBentPitch($bentPitch) {
			return ($bentPitch <= self::MAX_BEND_PITCH);
		}
		 
		 
		 
		function IsValidReleasePitch($releasePitch) {
			return ($releasePitch <= self::MAX_BEND_PITCH);
		}
		 
		 
		 
		function IsValidBendDuration($duration) {
			return ($duration <= self::MAX_BEND_DURATION);
		}
		 
		 
		 
		function IsValidDrawStartPoint($drawStartPoint) {
			return ($drawStartPoint <= self::highPoint);
		}
		 
		 
		 
		function IsValidDrawEndPoint($drawEndPoint) {
			return ($drawEndPoint <= self::highPoint);
		}
		 
		// Tapped Harmonic Functions
		 
		 
		 
		function IsValidTappedFretNumber($tappedFretNumber) {
			return (($tappedFretNumber >= self::MIN_FRET_NUMBER) && ($tappedFretNumber <= self::MAX_FRET_NUMBER));
		}
		 
		 
		 
		function IsValidTappedHarmonic($tappedFretNumber) {
			return ($this->IsValidTappedFretNumber($tappedFretNumber));
		}
		 
		 
		// Trill Functions
		 
		 
		 
		function IsValidTrilledFretNumber($trilledFretNumber) {
			return (($trilledFretNumber >= self::MIN_FRET_NUMBER) && ($trilledFretNumber <= self::MAX_FRET_NUMBER));
		}
		 
		 
		 
		function IsValidTrill($trilledFretNumber) {
			return ($this->IsValidTrilledFretNumber($trilledFretNumber));
		}
		 
		 
		// Artificial Harmonic Functions
		 
		 
		 
		function IsValidArtificialHarmonicOctave($octave) {
			return ($octave <= self::artificialHarmonicOctave15ma);
		}
		 
		 
		 
		function IsValidArtificialHarmonic($key, $keyVariation, $octave) {
			return (ChordName::IsValidKeyAndVariation($key, $keyVariation) && $this->IsValidArtificialHarmonicOctave($octave));
		}
		 
		 
		// Complex Symbol Array Functions
		 
		 
		 
		function IsValidComplexSymbolType($type) {
			return (($type == self::slide) || ($type == self::bend) || ($type == self::tappedHarmonic) || ($type == self::tappedHarmonic) || ($type == self::trill) || ($type == self::artificialHarmonic));
		}
		 
		 
		// Constructor/Destructor
		 
		 
		 
		function Note($string = NULL, $fretNumber = NULL) {
			 
			//------Last Checked------//
			// - Jan 17, 2005
			if (!$this->IsValidString($string)) return 0;
			if (!$this->IsValidFretNumber($fretNumber)) return 0;
			 
			$this->SetString($string);
			$this->SetFretNumber($fretNumber);
			$this->ClearComplexSymbolArrayContents();
		}
		 
		 
		 
		 
		 
		// Serialization Functions
		 
		function DoSerialize(&$stream){
		 

			WRITE_BYTE ($stream,$this->m_stringData);
			WRITE_WORD ($stream,$this->m_simpleData);

			$symbolCount = $this->GetComplexSymbolCount();
			WRITE_BYTE ($stream,$symbolCount);

			$i = 0;
			for (; $i < $symbolCount; $i++) {
				WRITE_INTEGER ($stream,$this->m_complexSymbolArray[$i]);
			}
			return 1;
		}
		
		 
		 
		function DoDeserialize(&$stream){
		 
		 
			$this->m_stringData = READ_BYTE ($stream);
			$this->m_simpleData = READ_WORD ($stream);
		
		
			$symbolCount = READ_BYTE ($stream);
		 
			$i = 0;
			for (; $i < $symbolCount; $i++) {
				$this->m_complexSymbolArray[$i] = READ_INTEGER ($stream);
			}
		 
		}
		
		// String Functions
		 
		 
		 
		function SetString($string) {
			 
			//------Last Checked------//
			// - Jan 17, 2005
			if (!$this->IsValidString($string)) return 0;
			 
			$this->m_stringData &= ~self::stringMask;
			$this->m_stringData |= ($string << 5);
			 
			return 1;
		}
		 
		 
		 
		function GetString() {
			 
			//------Last Checked------//
			// - Jan 17, 2005
			return (($this->m_stringData & self::stringMask) >> 5);
		}
		 
		// Fret Number Functions
		 
		 
		 
		function SetFretNumber($fretNumber) {
			 
			//------Last Checked------//
			// - Jan 17, 2005
			if (!$this->IsValidFretNumber($fretNumber)) return 0;
			 
			$this->m_stringData &= ~self::fretNumberMask;
			$this->m_stringData |= $fretNumber;
			 
			return 1;
		}
		 
		 
		 
		function GetFretNumber() {
			 
			//------Last Checked------//
			// - Jan 17, 2005
			return (($this->m_stringData & self::fretNumberMask));
		}
		 
		// Simple Flag Functions
		 
		 
		 
		function SetSimpleFlag($flag) {
			 
			//------Last Checked------//
			// - Jan 24, 2005
			if (!$this->IsValidSimpleFlag($flag)) return 0;
			 
			// Mutually exclusive operations
			if (($flag & self::hammerPullMask) != 0)
				$this->ClearSimpleFlag(self::hammerPullMask);
			 
			if (($flag & self::octaveMask) != 0)
				$this->ClearSimpleFlag(self::octaveMask);
			 
			$this->m_simpleData |= $flag;
			return 1;
		}
		 
		// Slide Into Functions
		 
		 
		 
		function SetSlideInto($type) {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			if (!$this->IsValidSlideInto($type)) return 0;
			 
			if ($type == self::slideIntoNone)
				return ($this->ClearSlideInto());
			 
			// Look for an existing self::slide first
			$index = $this->FindComplexSymbol(self::slide);
			 
			// Slide exists; update its self::slide into data
			if ($index != -1) {
				 
				$this->m_complexSymbolArray[$index] &= ~self::slideIntoTypeMask;
				$this->m_complexSymbolArray[$index] |= ($type << 16);
				return 1;
			}
			 
			// Construct the symbol data, then add it to the array
			$symbolData = MAKELONG(MAKEWORD(0, 0), MAKEWORD($type, self::slide));
			return ($this->AddComplexSymbol($symbolData));
		}
		 
		 
		 
		 
		function GetSlideInto(&$type) {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			 
			$type = self::slideIntoNone;
			 
			// Get the $index of the self::slide
			$index = $this->FindComplexSymbol(self::slide);
			if ($index == -1)
				return 0;
			 
			// Get the individual pieces that make up the self::slide into
			$symbolData = $this->m_complexSymbolArray[$index];
			$type = LOBYTE(HIWORD($symbolData));
			 
			return 1;
		}
		 
		 
		 
		function HasSlideInto() {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			 
			$type = self::slideIntoNone;
			if (!$this->GetSlideInto($type))
				return 0;
			return ($type != self::slideIntoNone);
		}
		 
		 
		 
		function ClearSlideInto() {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			 
			// Get the $index of the self::slide
			$index = $this->FindComplexSymbol(self::slide);
			if ($index == -1)
				return 0;
			 
			$this->m_complexSymbolArray[$index] &= ~self::slideIntoTypeMask;
			 
			// Return if there is a self::slide out, otherwise remove the self::slide symbol
			if ($this->HasSlideOutOf())
				return 1;
			 
			return ($this->RemoveComplexSymbol(self::slide));
		}
		 
		// Slide Out Of Functions
		 
		 
		 
		 
		function SetSlideOutOf($type, $steps) {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			if (!$this->IsValidSlideOutOf($type)) return 0;
			 
			if ($type == self::slideOutOfNone)
				return ($this->ClearSlideOutOf());
			 
			// Look for an existing self::slide first
			$index = $this->FindComplexSymbol(self::slide);
			 
			// Slide exists; update its self::slide out of data
			if ($index != -1) {
				 
				$this->m_complexSymbolArray[$index] &= ~(self::slideOutOfTypeMask | self::slideOutOfStepsMask);
				$this->m_complexSymbolArray[$index] |= ($type << 8);
				$this->m_complexSymbolArray[$index] |= ($steps);
				return 1;
			}
			 
			// Construct the symbol data, then add it to the array
			$symbolData = MAKELONG(MAKEWORD($steps, $type), MAKEWORD(0, self::slide));
			return ($this->AddComplexSymbol($symbolData));
		}
		 
		 
		 
		 
		 
		function GetSlideOutOf(&$type, &$steps) {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			 
			$type = self::slideIntoNone;
			$steps = 0;
			 
			// Get the $index of the self::slide
			$index = $this->FindComplexSymbol(self::slide);
			if ($index == -1)
				return 0;
			 
			// Get the individual pieces that make up the self::slide out of
			$symbolData = $this->m_complexSymbolArray[$index];
			$type = HIBYTE(LOWORD($symbolData));
			$steps = LOBYTE(LOWORD($symbolData));
			 
			return 1;
		}
		 
		 
		 
		function HasSlideOutOf() {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			 
			$type = self::slideOutOfNone;
			$steps = 0;
			if (!$this->GetSlideOutOf($type, $steps))
				return 0;
			return ($type != self::slideOutOfNone);
		}
		 
		 
		 
		function ClearSlideOutOf() {
			 
			//------Last Checked------//
			// - Jan 21, 2005
			 
			// Get the $index of the self::slide
			$index = $this->FindComplexSymbol(self::slide);
			if ($index == -1)
				return 0;
			 
			$this->m_complexSymbolArray[$index] &= ~(self::slideOutOfTypeMask | self::slideOutOfStepsMask);
			 
			// Return if there is a self::slide in, otherwise remove the self::slide symbol
			if ($this->HasSlideInto())
				return 1;
			 
			return ($this->RemoveComplexSymbol(self::slide));
		}
		 
		// Bend Functions
		 
		 
		 
		 
		 
		 
		 
		 
		function IsValidBend($type, $bentPitch, $releasePitch, $duration, $drawStartPoint, $drawEndPoint) {
			 
			
			// 1st validate the individual pieces
			if (!$this->IsValidBendType($type) || !$this->IsValidBentPitch($bentPitch) || !$this->IsValidReleasePitch($releasePitch) || !$this->IsValidBendDuration($duration) || !$this->IsValidDrawStartPoint($drawStartPoint) || !$this->IsValidDrawEndPoint($drawEndPoint))
				return 0;
			 
			$returnValue = 0;
			 
			if (($type == self::normalBend) || ($type == self::bendAndHold)) {
				 
				// a) Bent pitch must be greater than zero
				// b) Release pitch must be zero
				// c) Duration may be any value
				// d) Draw start must be low or mid and end must be higher
				$returnValue = (($bentPitch > 0) && ($releasePitch == 0) && ($drawStartPoint <= self::midPoint) && ($drawEndPoint > $drawStartPoint));
			}
			else if ($type == self::bendAndRelease) {
				 
				// a) Bent pitch must be greater than zero
				// b) Release pitch must be less than bent pitch
				// c) Duration must be zero
				// d) Draw start must be low or mid and $drawEndPoint must be low or mid
				$returnValue = (($bentPitch > 0) && ($releasePitch < $bentPitch) && ($duration == 0) && ($drawStartPoint <= self::midPoint) && ($drawEndPoint <= self::midPoint));
			}
			else if (($type == self::preBend) || ($type == self::preBendAndHold)) {
				 
				// a) Bent pitch must be greater than zero
				// b) Release pitch must be zero
				// c) Duration must be zero
				// d) Draw start must be low, and end must be higher
				$returnValue = (($bentPitch > 0) && ($releasePitch == 0) && ($duration == 0) && ($drawStartPoint == self::lowPoint) && ($drawEndPoint > $drawStartPoint));
			}
			else if ($type == self::preBendAndRelease) {
				 
				// a) Bent pitch must be greater than zero
				// b) Release pitch must be less than bent pitch
				// c) Duration must be zero
				// d) Draw start and end must be low
				$returnValue = (($bentPitch > 0) && ($releasePitch < $bentPitch) && ($duration == 0) && ($drawStartPoint == self::lowPoint) && ($drawEndPoint == self::lowPoint));
			}
			else if ($type == self::gradualRelease) {
				 
				// a) Bent pitch must be zero
				// b) Release pitch must be standard to 2 3/4
				// c) Duration must be > 0
				// d) Draw start must be high or mid point, draw end must be lower
				$returnValue = (($bentPitch == 0) && ($releasePitch <= 11) && ($duration > 0) && ($drawStartPoint >= self::midPoint) && ($drawEndPoint < $drawStartPoint));
			}
			else if ($type == self::immediateRelease) {
				 
				// a) Bent pitch must be zero
				// b) Release pitch must be zero
				// c) Duration must be zero
				// d) Draw start must be high or mid, and match draw end
				$returnValue = (($bentPitch == 0) && ($releasePitch == 0) && ($duration == 0) && ($drawStartPoint >= self::midPoint) && ($drawStartPoint == $drawEndPoint));
			}
			 
			return ($returnValue);
		}
		 
		 
		 
		 
		 
		function SetBend($type, $bentPitch, $releasePitch, $duration, $drawStartPoint, $drawEndPoint) {
			 
			
			if (!$this->IsValidBend($type, $bentPitch, $releasePitch, $duration, $drawStartPoint, $drawEndPoint)) return 0;
		
			// Construct the symbol data, then add it to the array
			$symbolData = MAKELONG(0, MAKEWORD(0, self::bend));
			$symbolData |= ($type << 20);
			$symbolData |= ($drawStartPoint << 18);
			$symbolData |= ($drawEndPoint << 16);
			$symbolData |= ($duration << 8);
			$symbolData |= ($bentPitch << 4);
			$symbolData |= ($releasePitch);
		 
			return ($this->AddComplexSymbol($symbolData));
		}
		 
		 
		 
		 
		 
		 
		 
		 
		 
		function GetBend(&$type, &$bentPitch, &$releasePitch, &$duration, &$drawStartPoint, &$drawEndPoint) {
			 
			//------Last Checked------//
			// - Jan 24, 2005
			$type = 0;
			$duration = 0;
			$bentPitch = 0;
			$releasePitch = 0;
			$drawStartPoint = 0;
			$drawEndPoint = 0;
			 
			// Get the $index of the self::bend
			$index = $this->FindComplexSymbol(self::bend);
			if ($index == -1)
				return 0;
			 
			// Get the individual pieces that make up the self::bend
			$symbolData = $this->m_complexSymbolArray[$index];
			 
			$type = (($symbolData & self::bendTypeMask) >> 20);
			$duration = HIBYTE(LOWORD($symbolData));
			$bentPitch = (($symbolData & self::bentPitchMask) >> 4);
			$releasePitch = ($symbolData & self::releasePitchMask);
			$drawStartPoint = (($symbolData & self::drawStartMask) >> 18);
			$drawEndPoint = (($symbolData & self::drawEndMask) >> 16);
			 
			return 1;
		}
		 
		 
		 
		function HasBend() {
			 
			//------Last Checked------//
			// - Jan 23, 2005
			return ($this->FindComplexSymbol(self::bend) != -1);
		}
		 
		 
		 
		function ClearBend() {
			 
			//------Last Checked------//
			// - Jan 23, 2005
			return ($this->RemoveComplexSymbol(self::bend));
		}
		 
		// Tapped Harmonic Functions
		 
		 
		 
		function SetTappedHarmonic($tappedFretNumber) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			if (!$this->IsValidTappedHarmonic($tappedFretNumber)) return 0;
			 
			// Construct the symbol data, then add it to the array
			$symbolData = MAKELONG(MAKEWORD($tappedFretNumber, 0), MAKEWORD(0, self::tappedHarmonic));
			return ($this->AddComplexSymbol($symbolData));
		}
		 
		 
		 
		 
		function GetTappedHarmonic(&$tappedFretNumber) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			 
			$tappedFretNumber = 0;
			 
			// Get the $index of the tapped harmonic
			$index = $this->FindComplexSymbol(self::tappedHarmonic);
			if ($index == -1)
				return 0;
			 
			// Get the individual pieces that make up the tapped harmonic
			$symbolData = $this->m_complexSymbolArray[$index];
			$tappedFretNumber = LOBYTE(LOWORD($symbolData));
			 
			return 1;
		}
		 
		 
		 
		function HasTappedHarmonic() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			return ($this->FindComplexSymbol(self::tappedHarmonic) != -1);
		}
		 
		 
		 
		function ClearTappedHarmonic() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			return ($this->RemoveComplexSymbol(self::tappedHarmonic));
		}
		 
		// Trill Functions
		 
		 
		 
		function SetTrill($trilledFretNumber) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			if (!$this->IsValidTrill($trilledFretNumber)) return 0;
			 
			// Construct the symbol data, then add it to the array
			$symbolData = MAKELONG(0, MAKEWORD($trilledFretNumber, self::trill));
			return ($this->AddComplexSymbol($symbolData));
		}
		 
		 
		 
		 
		function GetTrill(&$trilledFretNumber) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			 
			$trilledFretNumber = 0;
			 
			// Get the $index of the self::trill
			$index = $this->FindComplexSymbol(self::trill);
			if ($index == -1)
				return 0;
			 
			// Get the individual pieces that make up the self::trill
			$symbolData = $this->m_complexSymbolArray[$index];
			$trilledFretNumber = LOBYTE(HIWORD($symbolData));
			 
			return 1;
		}
		 
		 
		 
		function HasTrill() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			return ($this->FindComplexSymbol(self::trill) != -1);
		}
		 
		 
		 
		function ClearTrill() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			return ($this->RemoveComplexSymbol(self::trill));
		}
		 
		// Artificial Harmonic Functions
		 
		 
		 
		 
		 
		function SetArtificialHarmonic($key, $keyVariation, $octave) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			if (!$this->IsValidArtificialHarmonic($key, $keyVariation, $octave)) return 0;
			 
			// Construct the symbol data, then add it to the array
			$symbolData = MAKELONG(MAKEWORD($key, $keyVariation), MAKEWORD($octave, self::artificialHarmonic));
			return ($this->AddComplexSymbol($symbolData));
		}
		 
		 
		 
		 
		 
		 
		function GetArtificialHarmonic(&$key, &$keyVariation, &$octave) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			 
			$key = 0;
			$keyVariation = 0;
			$octave = 0;
			 
			// Get the $index of the artificial harmonic
			$index = $this->FindComplexSymbol(self::artificialHarmonic);
			if ($index == -1)
				return 0;
			 
			// Get the individual pieces that make up the artificial harmonic
			$symbolData = $this->m_complexSymbolArray[$index];
			$key = LOBYTE(LOWORD($symbolData));
			$keyVariation = HIBYTE(LOWORD($symbolData));
			$octave = LOBYTE(HIWORD($symbolData));
			 
			return 1;
		}
		 
		 
		 
		function HasArtificialHarmonic() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			return ($this->FindComplexSymbol(self::artificialHarmonic) != -1);
		}
		 
		 
		 
		function ClearArtificialHarmonic() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			return ($this->RemoveComplexSymbol(self::artificialHarmonic));
		}
		 
		// Complex Symbol Array Functions
		 
		 
		function AddTest ($s) {
			
			return ($this->m_complexSymbolArray[0] = $s);
		}
		
		function AddComplexSymbol($symbolData) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			 
			// Get and validate the symbol $type
			$type = HIBYTE(HIWORD($symbolData));
		
			if (!$this->IsValidComplexSymbolType($type)) return 0;
		
			$returnValue = 0;
			 
			// Get the $index in the complex array where the symbol is stored
			$index = $this->FindComplexSymbol($type);
			 
			// Found symbol in the array, update the symbol data
			if ($index != -1) {
				$this->m_complexSymbolArray[$index] = $symbolData;
				$returnValue = true;
			}
			// Symbol was not found in the array, find the first free array slot and insert there
			else {
				$i = 0;
				for (; $i < MAX_NOTE_COMPLEX_SYMBOLS; $i++) {
					 
					if ($this->m_complexSymbolArray[$i] == self::notUsed) {
						 
						$this->m_complexSymbolArray[$i] = $symbolData;
						$returnValue = true;
						break;
					}
				}
			}
			 
			return ($returnValue);
		}
		 
		 
		 
		function GetComplexSymbolCount() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			$returnValue = 0;
			$i = 0;
			for (; $i < MAX_NOTE_COMPLEX_SYMBOLS; $i++) {
				 
				// Slot is not used; break out
				if ($this->m_complexSymbolArray[$i] == self::notUsed)
					break;
				$returnValue++;
			}
			return ($returnValue);
		}
		 
		 
		 
		 
		function FindComplexSymbol($type) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			$returnValue = -1;
			 
			$i = 0;
			for (; $i < MAX_NOTE_COMPLEX_SYMBOLS; $i++) {
				 
				// Found the symbol $type; break out
				if (HIBYTE(HIWORD($this->m_complexSymbolArray[$i])) == $type) {
					 
					$returnValue = $i;
					break;
				}
			}
			 
			return ($returnValue);
		}
		 
		 
		 
		 
		function RemoveComplexSymbol($type) {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			$returnValue = 0;
			 
			$i = 0;
			for (; $i < MAX_NOTE_COMPLEX_SYMBOLS; $i++) {
				 
				if (HIBYTE(HIWORD($this->m_complexSymbolArray[$i])) == $type) {
					 
					$this->m_complexSymbolArray[$i] = self::notUsed;
					$returnValue = true;
					break;
				}
			}
			 
			return ($returnValue);
		}
		 
		 
		function ClearComplexSymbolArrayContents() {
			 
			//------Last Checked------//
			// - Jan 19, 2005
			$i = 0;
			for (; $i < MAX_NOTE_COMPLEX_SYMBOLS; $i++)
			$this->m_complexSymbolArray[$i] = self::notUsed;
		}
		 
		 
	}
	 
?>

